# -*- coding: utf-8 -*-
"""
乒乓球培训管理系统 - 用户账户模型
管理用户账户余额和交易记录
"""

from datetime import datetime
from decimal import Decimal
from flask_sqlalchemy import SQLAlchemy

from app import db


class UserAccount(db.Model):
    """
    用户账户模型
    管理用户的账户余额和统计信息
    """
    __tablename__ = 'user_accounts'

    # 基础字段
    id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
    user_id = db.Column(db.BigInteger, db.ForeignKey('users.id'),
                       unique=True, nullable=False, comment='用户ID')

    # 金额字段（使用Decimal避免浮点数精度问题）
    balance = db.Column(db.Numeric(10, 2), nullable=False, default=Decimal('0.00'), comment='账户余额')
    total_recharge = db.Column(db.Numeric(10, 2), nullable=False, default=Decimal('0.00'), comment='累计充值')
    total_consumption = db.Column(db.Numeric(10, 2), nullable=False, default=Decimal('0.00'), comment='累计消费')

    # 审计字段
    updated_at = db.Column(db.DateTime, nullable=False, default=datetime.now,
                          onupdate=datetime.now, comment='更新时间')

    def __init__(self, **kwargs):
        super(UserAccount, self).__init__(**kwargs)

    def get_balance_yuan(self):
        """获取余额（元）"""
        return float(self.balance) if self.balance else 0.0

    def get_total_recharge_yuan(self):
        """获取累计充值（元）"""
        return float(self.total_recharge) if self.total_recharge else 0.0

    def get_total_consumption_yuan(self):
        """获取累计消费（元）"""
        return float(self.total_consumption) if self.total_consumption else 0.0

    def has_sufficient_balance(self, amount):
        """检查余额是否充足"""
        return self.balance >= Decimal(str(amount))

    def recharge(self, amount, transaction_type='recharge', description=None, operator_id=None):
        """充值"""
        amount_decimal = Decimal(str(amount))
        if amount_decimal <= 0:
            return False, "充值金额必须大于0"

        # 更新账户余额
        self.balance += amount_decimal
        self.total_recharge += amount_decimal

        # 创建交易记录
        transaction = Transaction(
            user_id=self.user_id,
            type=transaction_type,
            amount=amount_decimal,
            balance_after=self.balance,
            description=description or f"账户充值 {amount}元",
            operator_id=operator_id
        )
        db.session.add(transaction)

        return True, "充值成功"

    def consume(self, amount, reservation_id=None, description=None):
        """消费扣费"""
        amount_decimal = Decimal(str(amount))
        if amount_decimal <= 0:
            return False, "扣费金额必须大于0"

        if not self.has_sufficient_balance(amount_decimal):
            return False, "账户余额不足"

        # 更新账户余额
        self.balance -= amount_decimal
        self.total_consumption += amount_decimal

        # 创建交易记录
        transaction = Transaction(
            user_id=self.user_id,
            reservation_id=reservation_id,
            type='consume',
            amount=-amount_decimal,  # 负数表示扣费
            balance_after=self.balance,
            description=description or f"课程费用 {amount}元"
        )
        db.session.add(transaction)

        return True, "扣费成功"

    def refund(self, amount, reservation_id=None, description=None):
        """退款"""
        amount_decimal = Decimal(str(amount))
        if amount_decimal <= 0:
            return False, "退款金额必须大于0"

        # 更新账户余额
        self.balance += amount_decimal
        # 注意：退款不减少累计消费，因为原消费记录仍然存在

        # 创建交易记录
        transaction = Transaction(
            user_id=self.user_id,
            reservation_id=reservation_id,
            type='refund',
            amount=amount_decimal,
            balance_after=self.balance,
            description=description or f"退款 {amount}元"
        )
        db.session.add(transaction)

        return True, "退款成功"

    @staticmethod
    def get_or_create_account(user_id):
        """获取或创建用户账户"""
        account = UserAccount.query.filter_by(user_id=user_id).first()
        if not account:
            account = UserAccount(user_id=user_id)
            db.session.add(account)
        return account

    def to_dict(self):
        """转换为字典格式"""
        return {
            'id': self.id,
            'user_id': self.user_id,
            'balance': float(self.balance) if self.balance else 0.0,
            'total_recharge': float(self.total_recharge) if self.total_recharge else 0.0,
            'total_consumption': float(self.total_consumption) if self.total_consumption else 0.0,
            'updated_at': self.updated_at.isoformat() if self.updated_at else None
        }

    def __repr__(self):
        return f'<UserAccount user_id={self.user_id} balance={self.balance}>'


class Transaction(db.Model):
    """
    交易记录模型
    记录所有的充值、消费、退款等交易
    """
    __tablename__ = 'transactions'

    # 基础字段
    id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
    user_id = db.Column(db.BigInteger, db.ForeignKey('users.id'),
                       nullable=False, comment='用户ID')
    reservation_id = db.Column(db.BigInteger, db.ForeignKey('reservations.id'),
                              nullable=True, comment='关联预约ID')

    # 交易信息
    type = db.Column(db.Enum('recharge', 'consume', 'refund'),
                    nullable=False, comment='交易类型')
    amount = db.Column(db.Numeric(8, 2), nullable=False, comment='交易金额')
    balance_after = db.Column(db.Numeric(10, 2), nullable=False, comment='交易后余额')

    # 支付信息
    payment_method = db.Column(db.Enum('wechat', 'alipay', 'offline'),
                              nullable=True, comment='支付方式')
    description = db.Column(db.String(255), nullable=True, comment='交易描述')

    # 操作信息
    operator_id = db.Column(db.BigInteger, db.ForeignKey('users.id'),
                           nullable=True, comment='操作员ID（线下充值）')

    # 审计字段
    created_at = db.Column(db.DateTime, nullable=False, default=datetime.now, comment='创建时间')

    # 关联关系
    user = db.relationship('User', foreign_keys=[user_id], backref='transactions')
    operator = db.relationship('User', foreign_keys=[operator_id])

    def __init__(self, **kwargs):
        super(Transaction, self).__init__(**kwargs)

    def get_amount_yuan(self):
        """获取交易金额（元）"""
        return float(self.amount) if self.amount else 0.0

    def get_balance_after_yuan(self):
        """获取交易后余额（元）"""
        return float(self.balance_after) if self.balance_after else 0.0

    def is_recharge(self):
        """是否为充值"""
        return self.type == 'recharge'

    def is_consume(self):
        """是否为消费"""
        return self.type == 'consume'

    def is_refund(self):
        """是否为退款"""
        return self.type == 'refund'

    def get_type_display(self):
        """获取交易类型显示文本"""
        type_map = {
            'recharge': '充值',
            'consume': '消费',
            'refund': '退款'
        }
        return type_map.get(self.type, self.type)

    def get_payment_method_display(self):
        """获取支付方式显示文本"""
        method_map = {
            'wechat': '微信支付',
            'alipay': '支付宝',
            'offline': '线下支付'
        }
        return method_map.get(self.payment_method, self.payment_method) if self.payment_method else '未知'

    @staticmethod
    def get_user_transactions(user_id, transaction_type=None, limit=None):
        """获取用户交易记录"""
        query = Transaction.query.filter_by(user_id=user_id)
        if transaction_type:
            query = query.filter_by(type=transaction_type)
        query = query.order_by(Transaction.created_at.desc())
        if limit:
            query = query.limit(limit)
        return query.all()

    def to_dict(self):
        """转换为字典格式"""
        return {
            'id': self.id,
            'user_id': self.user_id,
            'reservation_id': self.reservation_id,
            'type': self.type,
            'type_display': self.get_type_display(),
            'amount': float(self.amount) if self.amount else 0.0,
            'balance_after': float(self.balance_after) if self.balance_after else 0.0,
            'payment_method': self.payment_method,
            'payment_method_display': self.get_payment_method_display(),
            'description': self.description,
            'operator_id': self.operator_id,
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'operator_name': self.operator.real_name if self.operator else None
        }

    def __repr__(self):
        return f'<Transaction {self.type} {self.amount} for user {self.user_id}>'